package org.linlinjava.litemall.core.payment.clover.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.linlinjava.litemall.core.constant.LumiereCloverAPIConstant;
import org.linlinjava.litemall.core.constant.LumiereCloverConstant;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.payment.DefaultCurType;
import org.linlinjava.litemall.core.payment.clover.config.CloverConfig;
import org.linlinjava.litemall.core.payment.clover.dto.ApiChargeDTO;
import org.linlinjava.litemall.core.payment.clover.rq.ApiChargeRQ;
import org.linlinjava.litemall.core.payment.clover.service.GiftCardCloverService;
import org.linlinjava.litemall.core.util.AdminCouponDateUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.dto.CloverChargesDTO;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class GiftCardCloverServiceImpl implements GiftCardCloverService {

    private final CloverConfig cloverConfig;
    private final LitemallUserService litemallUserService;
    private final LitemallGiftCardUserService litemallGiftCardUserService;
    private final LitemallRechargeConsumptionService litemallRechargeConsumptionService;
    private final LitemallRechargeTransactionsService litemallRechargeTransactionsService;
    private final LitemallGiftCardOrderService litemallGiftCardOrderService;
    private final NoticeHelper noticeHelper;
    private final LitemallGiftCardUserLogService litemallGiftCardUserLogService;
    private final LumiereCloverChargesLogService lumiereCloverChargesLogService;
    private final LumiereCouponStrategyService lumiereCouponStrategyService;
    private final LumiereCouponUserService lumiereCouponUserService;
    private final LumiereCouponService lumiereCouponService;

    @SneakyThrows
    @Override
    @Transactional
    public ResponseUtil.Response executePayment(Integer userId, Integer shopId,String cardNumber,BigDecimal amount, String token) {
        if(userId == null){
            return ResponseUtil.unlogin();
        }
        LitemallUser user = litemallUserService.findById(userId);
        if(StrUtil.isEmpty(cardNumber)){
            return ResponseUtil.badArgument();
        }
        if(amount == null||amount.compareTo(new BigDecimal(0.00))<0){
            return ResponseUtil.badArgument();
        }
        //判断礼物卡效果
        LitemallGiftCardUser card = litemallGiftCardUserService.getOne(Wrappers.lambdaQuery(LitemallGiftCardUser.class)
                .eq(LitemallGiftCardUser::getUserId,userId)
                .eq(LitemallGiftCardUser::getCardNumber,cardNumber));
        if(card != null){
            if(!userId.equals(card.getUserId())){
                return ResponseUtil.fail(760, "用户礼物卡不存在");
            }
        }else{
            return ResponseUtil.fail(760,"礼物卡不存在");
        }

        //clover执行支付
        //支付体
        ApiChargeRQ apiChargeRQ = new ApiChargeRQ();
        apiChargeRQ.setAmount(amount.multiply(new BigDecimal(100)));
        apiChargeRQ.setCurrency(DefaultCurType.CAD.getType());
        apiChargeRQ.setSource(token);
        apiChargeRQ.setStored_credentials(new ApiChargeDTO("SUBSEQUENT",true,"CARDHOLDER"));
        //apiChargeRQ.setSource(cloverCard.getCustomerId());
        //开始交易
        OkHttpClient client = new OkHttpClient();

        MediaType mediaType = MediaType.parse(LumiereCloverConstant.APPLICATIONJSON);
        RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(apiChargeRQ));
        Request request = new Request.Builder()
                .url(LumiereCloverAPIConstant.CLOVER_EXECUTEPAYMENT)
                .post(body)
                .addHeader(LumiereCloverConstant.ACCEPT, LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.CONTENTTYPE, LumiereCloverConstant.APPLICATIONJSON)
                .addHeader(LumiereCloverConstant.IDEMPOTENCYKEY, IdUtil.simpleUUID())
                .addHeader(LumiereCloverConstant.AUTHORIZATION, String.format(LumiereCloverConstant.BEARER,cloverConfig.getAccessToken()))
                .build();

        Response response = client.newCall(request).execute();
        JSONObject vo =  JSON.parseObject(response.body().string());
        CloverChargesDTO cloverChargesDTO = JSON.toJavaObject(vo,CloverChargesDTO.class);
        //支付失败
        if(StrUtil.isBlank(cloverChargesDTO.getId())){
            log.info("clover card executePayment error : " + vo);
            String resultCode = StrUtil.sub(vo.getString("message"), 0, 3);
            return ResponseUtil.fail(Integer.parseInt(resultCode),vo.getString("error"));
        }
        long chargesLogId = IdUtil.createSnowflake(1, 1).nextId();
        //保存交易记录
        LumiereCloverChargesLog lumiereCloverChargesLog = LumiereCloverChargesLog.builder()
                .id(chargesLogId)
                .userId(userId)
                .shopId(shopId)
                .transactionId(cloverChargesDTO.getId())
                .amount(cloverChargesDTO.getAmount())
                .amountRefunded(cloverChargesDTO.getAmount_refunded())
                .currency(cloverChargesDTO.getCurrency())
                .created(cloverChargesDTO.getCreated())
                .captured(cloverChargesDTO.getCaptured())
                .refNum(cloverChargesDTO.getRef_num())
                .authCode(cloverChargesDTO.getAuth_code())
                .networkStatus(cloverChargesDTO.getOutcome().getNetwork_status())
                .type(cloverChargesDTO.getOutcome().getType())
                .paid(cloverChargesDTO.getPaid())
                .status(cloverChargesDTO.getStatus())
                .customerId(cloverChargesDTO.getSource().getId())
                .addressLine1(cloverChargesDTO.getSource().getAddress_line1())
                .addressLine1Check(cloverChargesDTO.getSource().getAddress_line1_check())
                .addressZip(cloverChargesDTO.getSource().getAddress_zip())
                .addressZipCheck(cloverChargesDTO.getSource().getAddress_zip_check())
                .brand(cloverChargesDTO.getSource().getBrand())
                .expMonth(cloverChargesDTO.getSource().getExp_month())
                .expYear(cloverChargesDTO.getSource().getExp_year())
                .first6(cloverChargesDTO.getSource().getFirst6())
                .last4(cloverChargesDTO.getSource().getLast4())
                .transactionType(2)
                .addTime(LocalDateTime.now())
                .deleted(false)
                .build();
        lumiereCloverChargesLogService.save(lumiereCloverChargesLog);

        //创建礼物卡订单
        LitemallGiftCardOrder order = new LitemallGiftCardOrder();
        order.setCurrency(DefaultCurType.CAD.getType());
        order.setAmount(amount);
        order.setUserId(userId);
        order.setCardNumber(card.getCardNumber());
        order.setGiftCardId(card.getGiftCardId());
        order.setShopId(shopId);
        order.setAddUserId(userId);

        order.setPayType((byte) 3);
        order.setPayStatus((byte) 2);
        order.setPayTime(LocalDateTime.now());
        litemallGiftCardOrderService.add(order);


        LitemallRechargeConsumption rechargeConsumption = new LitemallRechargeConsumption();
        rechargeConsumption.setUserId(user.getId());
        rechargeConsumption.setOrderId(order.getId());
        rechargeConsumption.setMobile(StrUtil.isNotEmpty(user.getMobile())?user.getMobile():null);
        rechargeConsumption.setUsername(user.getUsername());
        rechargeConsumption.setUserLevel(user.getUserLevel());
        rechargeConsumption.setAvailableAmount(user.getAvailableAmount());
        rechargeConsumption.setPoints(user.getPoints());
        rechargeConsumption.setType((byte) 2);
        rechargeConsumption.setAmount(amount);
        rechargeConsumption.setDeleted(false);
        rechargeConsumption.setAddUserId(userId);
        rechargeConsumption.setOrderSource((byte) 1);
        litemallRechargeConsumptionService.add(rechargeConsumption);

        //充值记录
        litemallRechargeTransactionsService.save(new LitemallRechargeTransactions()
                .setUserId(user.getId())
                .setCardNo(card.getCardNumber())
                .setShopId(shopId)
                .setUsername(user.getUsername())
                .setRechargeType(Constants.RECHARGE_TYPE_GIFT_CARD)
                .setPayType(Constants.PAY_TYPE_CLOVER)
                .setRechargeAmount(amount)
                .setRechargeSource(Constants.ORDER_SOURCE_APP)
        );

        //充值礼物卡
        card.setAmount(card.getAmount().add(amount));
        litemallGiftCardUserService.updateWithOptimisticLocker(card, card.getUpdateTime());
        log(cardNumber, Constants.LOG_GIFTCARD_RECHARGE,order.getId() ,"clover recharged"+order.getAmount(),userId,amount,shopId,card.getId(),card.getAmount());
        noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,"Your gift card notification", String.format("You have successfully recharged your gift card [ %s ]",cardNumber), userId, order);

        //赠送充值策略
        List<LumiereCouponStrategy> lumiereCouponStrategies = lumiereCouponStrategyService.list(Wrappers.lambdaQuery(LumiereCouponStrategy.class)
                .eq(LumiereCouponStrategy::getCouponType, 8)
                .eq(LumiereCouponStrategy::getStatus, 1)
                .le(LumiereCouponStrategy::getRechargeAmount,amount));
        if (!lumiereCouponStrategies.isEmpty()){
            List couponName = CollUtil.newArrayList();
            lumiereCouponStrategies.stream().forEach(couponStrategie->{
                //开始发券
                for (int i = 1;i<=couponStrategie.getTotal();i++) {
                    long nextId = IdUtil.getSnowflake(2, 2).nextId();
                    LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(couponStrategie);
                    LitemallUser litemallUser = litemallUserService.findById(order.getUserId());
                    LumiereCouponUser lumiereCouponUser = LumiereCouponUser.builder()
                            .userId(order.getUserId())
                            .strategyId(couponStrategie.getId())
                            .couponId(couponStrategie.getCouponId())
                            .userName(litemallUser.getUsername())
                            .startTime(localDateTimes[0])
                            .endTime(localDateTimes[1])
                            .code(String.valueOf(nextId))
                            .addTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .deleted(false)
                            .build();
                    LumiereCoupon lumiereCoupon = lumiereCouponService.getById(couponStrategie.getCouponId());
                    couponName.add(lumiereCoupon.getName());
                    lumiereCouponUserService.save(lumiereCouponUser);
                }
            });
            //发送赠送券 系统消息给用户
            noticeHelper.noticeUser( Constants.MSG_TYPE_OTHER, LumiereCloverConstant.WX_BALANCE_CLOVER_RECHARGE_TITLE_NOTICEHELPER,
                    String.format(LumiereCloverConstant.WX_BALANCE_CLOVER_RECHARGE_GIVE_COUPON_NOTICEHELPER, order.getAmount(),couponName), order.getUserId(), null);
        }
        return ResponseUtil.ok(card.getCardNumber());
    }

    //记录日志
    @Async
    public void log(String cardNumber, Byte type,Integer giftOrderid, String content, Integer userId, BigDecimal amount, Integer shopId,Integer cardUserId,BigDecimal balance){
        LitemallUser user = litemallUserService.findById(userId);
        LitemallGiftCardUserLog log = new LitemallGiftCardUserLog();
        log.setCardNumber(cardNumber);
        log.setType(type);
        log.setAmount(amount);
        log.setAddUserId(userId);
        log.setContent(content);
        log.setOrderId(giftOrderid);
        log.setCardUserId(cardUserId);
        log.setBalance(balance);
        log.setShopId(shopId);
        log.setOrderSource(Constants.ORDER_SOURCE_APP);
        log.setContent(user.getUsername() + ":" + content);
        log.setAddUserName(user.getUsername());
        log.setChangePoints(BigDecimal.ZERO);
        litemallGiftCardUserLogService.add(log);
    }
}
